package com.clhbolg.service.impl;

import cn.dev33.satoken.filter.SaServletFilter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clhbolg.domain.Resource;
import com.clhbolg.domain.bo.ResourceBo;
import com.clhbolg.domain.vo.ResourceVo;
import com.clhbolg.mapper.ResourceMapper;
import com.clhbolg.match.ExcludesInterceptor;
import com.clhbolg.model.dto.ResourceDTO;
import com.clhbolg.model.vo.request.ResourceVO;
import com.clhbolg.service.IResourceService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.properties.SecurityProperties;
import com.ruoyi.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.SpringDocConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 【接口资源】Service业务层处理
 *
 * @author cailinhu
 * @date 2023-02-08
 */
@RequiredArgsConstructor
@Service
@DS("slave")
public class ResourceServiceImpl implements IResourceService {

    private final ResourceMapper baseMapper;
    @Autowired
    SpringDocConfigProperties springDocConfigProperties;

    @Autowired
    Environment environment;

//    @Autowired
    SaServletFilter saServletFilter;
    @Autowired
    SecurityProperties securityProperties;


    @Override
    @Transactional
    public void importSwagger() {
        List<Resource> resourceByIsAnonymous = this.getResourceByIsAnonymous(1);
        Map<String, Integer> oldUrlMap = resourceByIsAnonymous.stream().collect(Collectors.toMap(e->e.getUrl()+":"+e.getRequestMethod(), Resource::getIsAnonymous));
        this.baseMapper.delete(null);
        List<SpringDocConfigProperties.GroupConfig> groupConfigs = springDocConfigProperties.getGroupConfigs();
        SpringDocConfigProperties.GroupConfig groupConfig = groupConfigs.get(groupConfigs.size() - 1);
        String path = springDocConfigProperties.getApiDocs().getPath();
        if (StrUtil.isEmpty(path)) path="/v3/api-docs";
        String port = environment.getProperty("server.port");
        String uri="http://localhost:"+port+path+"/"+groupConfig.getGroup();
        JSONObject entries = JSONUtil.parseObj(HttpUtil.get(uri));
        List<Map> tags = entries.getBeanList("tags", Map.class);
        Object paths = entries.getJSONObject("paths");
        List<Resource> resources = new ArrayList<>();
        tags.forEach(m->{
            Object name = m.get("name");
            Resource build = Resource.builder().resourceName(name.toString()).isAnonymous(0).build();
            resources.add(build);
        });
        baseMapper.insertBatch(resources);
        Map<String, Long> permissionMap = resources.stream()
            .collect(Collectors.toMap(Resource::getResourceName, Resource::getId));
        resources.clear();
        Map<String, Map<String, Map<String, Object>>> p = (Map<String, Map<String, Map<String, Object>>>) paths;
        p.forEach((url, value) -> value.forEach((requestMethod, info) -> {
            Object summary = info.get("summary");
            if (Objects.isNull(summary)) throw new GlobalException(url+":未添加接口信息!");
            String permissionName = summary.toString();
            List<String> tag = (List<String>) info.get("tags");
            Long parentId = permissionMap.get(tag.get(0));
            Integer isAnonymous=0;
            if (CollUtil.isNotEmpty(oldUrlMap)){
                if (oldUrlMap.containsKey(url+":"+requestMethod.toUpperCase())){
                    isAnonymous=oldUrlMap.get(url+":"+requestMethod.toUpperCase());
                }
            }
            Resource resource = Resource.builder()
                .resourceName(permissionName)
//                .url(url.replaceAll("\\{[^}]*\\}", "*"))
                .url(url)
                .parentId(parentId)
                .requestMethod(requestMethod.toUpperCase())
                .isAnonymous(isAnonymous)
                .build();
            resources.add(resource);
        }));
        baseMapper.insertBatch(resources);
    }

    /**
     * 查询【接口资源】
     */
    @Override
    public ResourceVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询【接口资源】列表
     */
    @Override
    public TableDataInfo<ResourceVo> queryPageList(ResourceBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Resource> lqw = buildQueryWrapper(bo);
        Page<ResourceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询【接口资源】列表
     */
    @Override
    public List<ResourceVo> queryList(ResourceBo bo) {
        LambdaQueryWrapper<Resource> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Resource> buildQueryWrapper(ResourceBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Resource> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getResourceName()), Resource::getResourceName, bo.getResourceName());
        lqw.eq(StringUtils.isNotBlank(bo.getUrl()), Resource::getUrl, bo.getUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getRequestMethod()), Resource::getRequestMethod, bo.getRequestMethod());
        lqw.eq(bo.getParentId() != null, Resource::getParentId, bo.getParentId());
        lqw.eq(bo.getIsAnonymous() != null, Resource::getIsAnonymous, bo.getIsAnonymous());
        return lqw;
    }

    /**
     * 新增【接口资源】
     */
    @Override
    public Boolean insertByBo(ResourceBo bo) {
        Resource add = BeanUtil.toBean(bo, Resource.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改【接口资源】
     */
    @Override
    public Boolean updateByBo(ResourceBo bo) {
        Resource update = BeanUtil.toBean(bo, Resource.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Resource entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除【接口资源】
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 需要统计归类父子关系
     * @param keywords
     * @return
     */
    @Override
    public List<ResourceDTO> queryList(String keywords) {
        ResourceBo resourceBo = new ResourceBo();
        resourceBo.setResourceName(keywords);
        List<ResourceVo> list = this.queryList(resourceBo);
        List<ResourceVo> parents = list.stream().filter(e -> e.getParentId()==null).collect(Collectors.toList());
        Map<Long, List<ResourceVo>> childs = list.stream().filter(e -> e.getParentId()!=null).collect(Collectors.groupingBy(ResourceVo::getParentId));
        for (ResourceVo resourceVo : parents) {
            if (childs!=null&&!childs.containsKey(resourceVo.getId())){
                //单独查询出对应的子菜单
                List<ResourceVo> ResourceChild = baseMapper.selectVoList(Wrappers.lambdaQuery(Resource.class).eq(Resource::getParentId, resourceVo.getId()));
                childs.put(resourceVo.getId(),ResourceChild);
            }
        }

        List<ResourceDTO> collect = parents.stream().map(p -> {
            ResourceDTO resourceDTO = Convert.convert(ResourceDTO.class, p);
            List<ResourceVo> child = childs.get(resourceDTO.getId());
            resourceDTO.setChildren(Convert.toList(ResourceDTO.class, child));
            childs.remove(resourceDTO.getId());
            return resourceDTO;
        }).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(childs)){
            //如果还有没有匹配上的,就直接加入到集合里面去
            List<ResourceVo> childrenList = new ArrayList<>();
            childs.values().forEach(childrenList::addAll);
            List<ResourceDTO> childrenDTOs = childrenList.stream().map(item -> {
                ResourceDTO resourceDTO = Convert.convert(ResourceDTO.class, item);
                return resourceDTO;
            }).collect(Collectors.toList());
            collect.addAll(childrenDTOs);
        }


        return collect;
    }
    @Autowired
    @Lazy
    ExcludesInterceptor excludesInterceptor;
    @Override
    public void saveOrUpdateResource(ResourceVO resourceVO) {
        Resource resource = Convert.convert(Resource.class,resourceVO);
        baseMapper.insertOrUpdate(resource);
        //更新过滤器规则
        excludesInterceptor.removeSecurityItem(resource);
        excludesInterceptor.updateSoToken();
    }

    @Override
    public List<Resource> getResourceByIsAnonymous(Integer isAnonymous) {
        List<Resource> resources = baseMapper.selectList(Wrappers.lambdaQuery(Resource.class).eq(Resource::getIsAnonymous,isAnonymous));
        return resources;
    }



}
